The purpose of exploratory analysis is to perform initial investigations on the data so as to discover patterns, identify any anomalies, to test initial hypothesis and check assumptions made at the start of the project.

In this section of the project we will ask two types of questions:

  1. what type of variation occurs within my variables?
  2. what type of covariation occurs between my variables?

Variation being the tendency for values of a variable to change from measurement to measurement, and covariance is the tendency for two or more variables to vary together in a related way.

pacman::p_load(
  tidyverse,
  here,
  RColorBrewer,
  lubridate,
  scales,
  GGally,
  stats,
  corrplot,
  mice,
  VIM
)
flights_dt <- read_csv(here("clean_data/flights_clean.csv"))
Rows: 327346 Columns: 38
── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr  (11): origin, origin_name, dest, dest_name, carrier, carrier_name, tailnum, manufacturer, model, engine, type
dbl  (22): dep_delay, arr_delay, air_time, distance, flight, engines, seats, aircraft_age, lat, lon, alt, wind_di...
dttm  (5): dep_time, sched_dep_time, arr_time, sched_arr_time, time_hour

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
cbPalette <- c("#999999", "#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7")

Which airport in our dataset has the highest number of departures?

flights_dt %>% 
  group_by(origin) %>%
  ggplot() +
  aes(x = origin, fill = origin) +
  geom_bar() +
  scale_fill_manual(values = cbPalette) +
  labs(
    x = "airport",
    y = "departure numbers",
    title = "Departure numbers by airport"
  ) +
  guides(fill = "none") +
  theme_bw()

What is the trend of delays over the year, how does it compare across the three airports?

flights_dt %>% 
  filter(dep_delay > 0) %>% 
  group_by(month = floor_date(sched_dep_time, "month"), origin) %>% 
  summarise(mean_delay = mean(dep_delay), .groups = "drop") %>% 
  ggplot() +
  aes(x = month, y = mean_delay, colour = origin) +
  geom_line(alpha = 0.6) +
  geom_point(alpha = 0.8) +
  labs(
    x = "month",
    y = "mean delay (minutes)",
    title = " Mean delay by month",
    colour = "airport"
  ) +
  scale_colour_manual(values = c("#999999", "#E69F00", "#56B4E9")) +
  theme_bw()

What is the number of departure delays over the year?

flights_dt %>%
  filter(dep_delay > 0) %>% 
  group_by(month = floor_date(sched_dep_time, "month"), origin) %>% 
  summarise(no_of_delays = n(), .groups = "drop") %>% 
  ggplot() +
  aes(x = month, y = no_of_delays, colour = origin) +
  geom_line(alpha = 0.6) +
  geom_point(alpha = 0.8) +
  labs(
    x = "month",
    y = "number of delays",
    title = " Monthly trend of departure delays",
    colour = "airport"
  ) +
  scale_colour_manual(values = c("#999999", "#E69F00", "#56B4E9")) +
  theme_bw()

What is the number of flights per month?

flights_dt %>%
  mutate(month = month(sched_dep_time, label = TRUE)) %>% 
  group_by(month, origin) %>% 
  summarise(no_of_flights = n(), .groups = "drop") %>% 
  ggplot() +
  aes(x = month, y = no_of_flights, fill = origin) +
  geom_col(position = "dodge", alpha = 0.8) +
  labs(
    x = "month",
    y = "number of departures",
    title = "Departure numbers by month",
    fill = "airport"
  ) +
  scale_fill_manual(values = cbPalette) +
  theme_bw()

Which carrier has the most departure delays?

flights_dt %>% 
  filter(dep_delay > 0) %>% 
  group_by(carrier_name, origin) %>% 
  summarise(mean_delay = mean(dep_delay), .groups = "drop") %>% 
  ggplot() +
  aes(x = reorder(carrier_name, mean_delay), y = mean_delay, fill = origin) +
  geom_col(alpha = 0.8) +
  facet_wrap(~ origin) +
  labs(
    x = "carrier",
    y = "mean delay (minutes)",
    title = "Mean departure delay by carrier",
    fill = "airport"
  ) +
  theme_bw() +
  scale_fill_manual(values=c("#999999", "#E69F00", "#56B4E9")) +
  theme(axis.text.x = element_text(angle = 0, vjust = 0.5, hjust = 1)) +
  coord_flip()

Which carrier has the most arrival delays?

flights_dt %>% 
  filter(arr_delay > 0) %>% 
  group_by(carrier_name, origin) %>% 
  summarise(mean_delay = mean(arr_delay), .groups = "drop") %>% 
  ggplot() +
  aes(x = reorder(carrier_name, mean_delay), y = mean_delay, fill = origin) +
  geom_col(alpha = 0.8) +
  facet_wrap(~ origin) +
  labs(
    x = "carrier",
    y = "mean delay (minutes)",
    title = "Mean arrival delay by carrier",
    fill = "airport"
  ) +
  theme_bw() +
  scale_fill_manual(values=c("#999999", "#E69F00", "#56B4E9")) +
  theme(axis.text.x = element_text(angle = 0, vjust = 0.5, hjust = 1)) +
  coord_flip()

Which season has the highest number of departure delays?

flights_dt %>% 
  filter(dep_delay > 0) %>% 
  group_by(day = floor_date(sched_dep_time, "day"), origin) %>% 
  summarise(mean_delay = mean(dep_delay, na.rm = TRUE), .groups = "drop") %>% 
  ggplot() +
  aes(x = day, y = mean_delay, colour = origin) +
  geom_point(alpha = 0.8) +
  labs(
    x = "date",
    y = "mean delay (minutes)",
    title = "Mean departure delay by month"
  ) +
  scale_colour_manual(values = c("#999999", "#E69F00", "#56B4E9")) +
  theme_bw()

Over the course of a day when is the largest average delay?

flights_dt %>% 
  filter(dep_delay > 0 & origin == "EWR") %>% 
  select(dep_delay, hour) %>%
  group_by(hour) %>% 
  summarise(mean_delay = mean(dep_delay, na.rm = TRUE), .groups = "drop") %>% 
  ggplot() +
  aes(x = hour, y = mean_delay) +
  geom_point(alpha = 0.8, colour = "#56B4E9") +
  geom_smooth(se = FALSE, colour = "#E69F00") +
  labs(
    x = "hour",
    y = "mean delay (minutes)",
    title = "Mean departure delay by departure time"
  ) +
  theme_bw() +
  scale_x_continuous(limits = c(5, 23), breaks = seq(5, 23, by = 1))
`geom_smooth()` using method = 'loess' and formula 'y ~ x'

Which day is the best day to travel from Newark Int.?

flights_dt %>%
  filter(dep_delay > 0 & origin == "EWR") %>% 
  mutate(weekday = wday(sched_dep_time, label = TRUE)) %>% 
  group_by(weekday) %>% 
  summarise(mean_delay = mean(dep_delay)) %>% 
  ggplot() +
  aes(x = weekday, y = mean_delay) +
    geom_col(fill = "#999999", alpha = 0.8) +
  labs(
    x = "weekday",
    y = "mean departure delay (minutes)",
    title = "Departure delay by weekday"
  ) +
  theme_bw()

Which destinations suffer from the longest delays?

flights_dt %>%
  drop_na(dest_name) %>% 
  filter(dep_delay > 0 & origin == "EWR") %>% 
  group_by(dest, dest_name) %>% 
  summarise(mean_delay = mean(dep_delay, na.rm = TRUE), .groups = "drop") %>% 
  arrange(desc(mean_delay)) %>% 
  head(10) %>% 
  ggplot() +
  aes(x = reorder(dest_name, mean_delay), y = mean_delay) +
  geom_col(fill = "#999999", alpha = 0.8) +
  labs(
    x = "destination",
    y = "mean delay (minutes)",
    title = "Destinations with longest delays"
  ) +
  theme_bw() +
  coord_flip()

Trend weather conditions against mean departure delays

flights_dt %>% 
  filter(dep_delay > 0 & origin == "EWR") %>% 
  group_by(day = floor_date(sched_dep_time, "day"), origin) %>% 
  summarise(mean_visibility = mean(visib, na.rm = TRUE),
            mean_delay = mean(dep_delay), .groups = "drop") %>% 
  ggplot() +
  aes(x = mean_visibility, y = mean_delay) +
  geom_point(alpha = 0.7) +
  geom_smooth(method = "lm", se = FALSE, colour = "#E69F00") +
  labs(
    x = "mean visibility (miles)",
    y = "mean departure delay (minutes)",
    title = "Mean departure delay by visibility"
  ) +
  theme_bw()
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 1 rows containing non-finite values (stat_smooth).
Warning: Removed 1 rows containing missing values (geom_point).

flights_dt %>% 
  filter(dep_delay > 0 & origin == "EWR") %>% 
  group_by(day = floor_date(sched_dep_time, "day"), origin) %>% 
  summarise(mean_wind_speed = mean(wind_speed, na.rm = TRUE),
            mean_delay = mean(dep_delay)) %>% 
  ggplot() +
  aes(x = mean_wind_speed, y = mean_delay) +
  geom_point(alpha = 0.7) +
  geom_smooth(method = "lm", se = FALSE, colour = "#E69F00") +
  labs(
    x = "mean wind speed (mph)",
    y = "mean departure delay (minutes)",
    title = "Mean departure delay by wind speed"
  ) +
  theme_bw()
`summarise()` has grouped output by 'day'. You can override using the `.groups` argument.
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 1 rows containing non-finite values (stat_smooth).
Warning: Removed 1 rows containing missing values (geom_point).

flights_dt %>% 
  filter(dep_delay > 0 & origin == "EWR") %>% 
  group_by(day = floor_date(sched_dep_time, "day"), origin) %>% 
  summarise(mean_wind_dir = mean(wind_dir, na.rm = TRUE),
            mean_delay = mean(dep_delay)) %>% 
  ggplot() +
  aes(x = mean_wind_dir, y = mean_delay) +
  geom_point(alpha = 0.7) +
  geom_smooth(method = "lm", se = FALSE, colour = "#E69F00") +
  labs(
    x = "mean wind direction (degrees)",
    y = "mean departure delay (minutes)",
    title = "Mean departure delay by wind direction"
  ) +
  theme_bw()
`summarise()` has grouped output by 'day'. You can override using the `.groups` argument.
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 1 rows containing non-finite values (stat_smooth).
Warning: Removed 1 rows containing missing values (geom_point).

flights_dt %>%
  filter(dep_delay > 0 & origin == "EWR") %>% 
  group_by(day = floor_date(sched_dep_time, "day"), origin) %>% 
  summarise(mean_humidity = mean(humid, na.rm = TRUE),
            mean_delay = mean(dep_delay)) %>% 
  ggplot() +
  aes(x = mean_humidity, y = mean_delay) +
  geom_point(alpha = 0.7) +
  geom_smooth(method = "lm", se = FALSE, colour = "#E69F00") +
  labs(
    x = "mean humidity (%)",
    y = "mean departure delay (minutes)",
    title = "Mean departure delay by humidity"
  ) +
  theme_bw()
`summarise()` has grouped output by 'day'. You can override using the `.groups` argument.
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 1 rows containing non-finite values (stat_smooth).
Warning: Removed 1 rows containing missing values (geom_point).

flights_dt %>% 
  filter(dep_delay > 0 & origin == "EWR") %>% 
  group_by(day = floor_date(sched_dep_time, "day"), origin) %>% 
  summarise(mean_temp = mean(temp, na.rm = TRUE),
            mean_delay = mean(dep_delay)) %>% 
  ggplot() +
  aes(x = mean_temp, y = mean_delay) +
  geom_point(alpha = 0.7) +
  geom_smooth(method = "lm", se = FALSE, colour = "#E69F00") +
  labs(
    x = "mean temperature (degf)",
    y = "mean departure delay (minutes)",
    title = "Mean departure delay by temperature"
  ) +
  theme_bw()
`summarise()` has grouped output by 'day'. You can override using the `.groups` argument.
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 1 rows containing non-finite values (stat_smooth).
Warning: Removed 1 rows containing missing values (geom_point).

flights_dt %>% 
  filter(dep_delay > 0 & origin == "EWR") %>% 
  group_by(day = floor_date(sched_dep_time, "day"), origin) %>% 
  summarise(mean_dewpoint = mean(dewp, na.rm = TRUE),
            mean_delay = mean(dep_delay)) %>% 
  ggplot() +
  aes(x = mean_dewpoint, y = mean_delay) +
  geom_point(alpha = 0.7) +
  geom_smooth(method = "lm", se = FALSE, colour = "#E69F00") +
  labs(
    x = "mean dewpoint (degF)",
    y = "mean departure delay (minutes)",
    title = "Mean departure delay by dewpoint"
  ) +
  theme_bw()
`summarise()` has grouped output by 'day'. You can override using the `.groups` argument.
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 1 rows containing non-finite values (stat_smooth).
Warning: Removed 1 rows containing missing values (geom_point).

flights_dt %>% 
  filter(dep_delay > 0 & origin == "EWR") %>% 
  group_by(day = floor_date(sched_dep_time, "day"), origin) %>% 
  summarise(mean_precip = mean(precip, na.rm = TRUE),
            mean_delay = mean(dep_delay)) %>% 
  ggplot() +
  aes(x = mean_precip, y = mean_delay) +
  geom_point(alpha = 0.7) +
  geom_smooth(method = "lm", se = FALSE, colour = "#E69F00") +
  labs(
    x = "mean precipitation (inches)",
    y = "mean departure delay (minutes)",
    title = "Mean departure delay by precipitation"
  ) +
  theme_bw()
`summarise()` has grouped output by 'day'. You can override using the `.groups` argument.
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 1 rows containing non-finite values (stat_smooth).
Warning: Removed 1 rows containing missing values (geom_point).

flights_dt %>%
  filter(dep_delay > 0 & origin == "EWR") %>% 
  group_by(day = floor_date(sched_dep_time, "day"), origin) %>% 
  summarise(mean_pressure = mean(pressure, na.rm = TRUE),
            mean_delay = mean(dep_delay)) %>% 
  ggplot() +
  aes(x = mean_pressure, y = mean_delay) +
  geom_point(alpha = 0.7) +
  geom_smooth(method = "lm", se = FALSE, colour = "#E69F00") +
  labs(
    x = "mean pressure (mbar)",
    y = "mean departure delay (minutes)",
    title = "Mean departure delay by pressure"
  ) +
  theme_bw()
`summarise()` has grouped output by 'day'. You can override using the `.groups` argument.
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 1 rows containing non-finite values (stat_smooth).
Warning: Removed 1 rows containing missing values (geom_point).

Corrplot

# subset the flights dataset so as to drop NAs, filter on only departure delays (no early departures) and only for Newark Int.
flights_weather <- flights_dt %>% 
  na.omit() %>% 
  filter(dep_delay > 0 & origin == "EWR") %>% 
  select(dep_delay, temp, dewp, humid, wind_dir, wind_speed, precip, pressure, visib)

# create correlation matrix
cor_matrix <- cor(flights_weather)
corrplot(cor_matrix, type = "upper", col = cbPalette,
         tl.col = "black", method = "number")

ggpairs

ggpairs(flights_weather)

Linear regression modeling

model_1_dt <- flights_dt %>% 
  na.omit() %>% 
  filter(dep_delay > 0 & origin == "EWR") %>% 
  select(dep_delay, temp, dewp, humid, wind_dir, wind_speed, precip, pressure, visib)

model_1 <- lm(dep_delay ~ ., data = model_1_dt)

# view results 
summary(model_1)

Call:
lm(formula = dep_delay ~ ., data = model_1_dt)

Residuals:
   Min     1Q Median     3Q    Max 
-59.90 -29.00 -16.77  10.88 815.29 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept) 631.659739  40.355182  15.653  < 2e-16 ***
temp          0.463713   0.135562   3.421 0.000625 ***
dewp         -0.435947   0.145838  -2.989 0.002798 ** 
humid         0.467200   0.076075   6.141 8.26e-10 ***
wind_dir     -0.017681   0.002832  -6.243 4.33e-10 ***
wind_speed    0.486040   0.054098   8.985  < 2e-16 ***
precip       -8.181936  17.295980  -0.473 0.636177    
pressure     -0.623965   0.038058 -16.395  < 2e-16 ***
visib         0.297599   0.213728   1.392 0.163802    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 48.57 on 40553 degrees of freedom
Multiple R-squared:  0.025, Adjusted R-squared:  0.02481 
F-statistic:   130 on 8 and 40553 DF,  p-value: < 2.2e-16

Relationship between weather variables

flights_dt %>%
  filter(dep_delay > 0 & origin == "EWR") %>% 
  na.omit() %>% 
  ggplot() +
  aes(x = humid, y = dewp) +
  geom_point()


flights_dt %>%
  filter(dep_delay > 0 & origin == "EWR") %>% 
  na.omit() %>% 
  ggplot() +
  aes(x = temp, y = dewp) +
  geom_point()


flights_dt %>%
  filter(dep_delay > 0 & origin == "EWR") %>% 
  na.omit() %>% 
  ggplot() +
  aes(x = visib, y = humid) +
  geom_point()


flights_dt %>%
  filter(dep_delay > 0 & origin == "EWR") %>% 
  na.omit() %>% 
  ggplot() +
  aes(x = dewp, y = pressure) +
  geom_point()


flights_dt %>%
  filter(dep_delay > 0 & origin == "EWR") %>% 
  na.omit() %>% 
  ggplot() +
  aes(x = humid, y = wind_speed) +
  geom_point()

Linear regression model with interactions in weather variables

summary(model_3)

Call:
lm(formula = dep_delay ~ air_time + aircraft_age + alt + hour + 
    dewp + pressure + dewp:humid + pressure:dewp + dewp:temp + 
    wind_speed:humid, data = model_2_dt)

Residuals:
   Min     1Q Median     3Q    Max 
-86.30 -27.15 -13.92   9.77 815.55 

Coefficients:
                   Estimate Std. Error t value Pr(>|t|)    
(Intercept)      -4.705e+02  7.388e+01  -6.369 1.92e-10 ***
air_time         -5.057e-02  2.425e-03 -20.853  < 2e-16 ***
aircraft_age      2.366e-01  4.810e-02   4.918 8.79e-07 ***
alt               1.059e-03  2.286e-04   4.633 3.62e-06 ***
hour              1.737e+00  5.498e-02  31.597  < 2e-16 ***
dewp              2.577e+01  1.827e+00  14.105  < 2e-16 ***
pressure          4.728e-01  7.222e-02   6.547 5.93e-11 ***
dewp:humid        7.640e-03  4.174e-04  18.303  < 2e-16 ***
dewp:pressure    -2.607e-02  1.768e-03 -14.745  < 2e-16 ***
dewp:temp         3.842e-03  6.260e-04   6.138 8.43e-10 ***
humid:wind_speed  7.562e-03  8.812e-04   8.581  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 47.4 on 40551 degrees of freedom
Multiple R-squared:  0.07124,   Adjusted R-squared:  0.07101 
F-statistic: 311.1 on 10 and 40551 DF,  p-value: < 2.2e-16

glmulti

glmulti_fit <- glmulti(
  dep_delay ~ ., 
  data = flights_weather,
  level = 2, # 2 = include pairwise interactions, 1 = main effects only (main effect = no pairwise interactions)
  minsize = 0, # no min size of model
  maxsize = -1, # -1 = no max size of model
  marginality = TRUE, # marginality here means the same as 'strongly hierarchical' interactions, i.e. include pairwise interactions only if both predictors present in the model as main effects.
  method = "g", # the problem is too large for exhaustive search, so search using a genetic algorithm
  crit = bic, # criteria for model selection is BIC value (lower is better)
  plotty = FALSE, # don't plot models as function runs
  report = TRUE, # do produce reports as function runs
  confsetsize = 10, # return best 100 solutions
  fitfunction = lm # fit using the `lm` function
)

Decision Tree

str(flights_decision_tree)
tibble [91,968 × 19] (S3: tbl_df/tbl/data.frame)
 $ distance      : num [1:91968] 1400 719 1065 2227 1023 ...
 $ engines       : Factor w/ 2 levels "1","2": 2 2 2 2 2 2 2 2 2 2 ...
 $ engine        : Factor w/ 6 levels "4 Cycle","Reciprocating",..: 3 3 3 3 3 3 3 3 4 3 ...
 $ aircraft_age  : num [1:91968] 22 9 21 13 15 31 12 20 22 19 ...
 $ lat           : num [1:91968] 30 42 26.1 36.1 26.7 ...
 $ lon           : num [1:91968] -95.3 -87.9 -80.2 -115.2 -80.1 ...
 $ alt           : num [1:91968] 97 668 9 2141 19 ...
 $ hour          : num [1:91968] 5 5 6 6 6 6 6 6 6 6 ...
 $ temp          : num [1:91968] 39 39 37.9 37.9 37.9 ...
 $ precip        : num [1:91968] 0 0 0 0 0 0 0 0 0 0 ...
 $ humid         : num [1:91968] 64.4 64.4 67.2 67.2 67.2 ...
 $ visib         : num [1:91968] 10 10 10 10 10 10 10 10 10 10 ...
 $ pressure      : num [1:91968] 1012 1012 1012 1012 1012 ...
 $ dewp          : num [1:91968] 28 28 28 28 28 ...
 $ wind_dir      : num [1:91968] 260 260 240 240 240 240 240 240 240 240 ...
 $ wind_speed    : num [1:91968] 12.7 12.7 11.5 11.5 11.5 ...
 $ month         : Ord.factor w/ 12 levels "Jan"<"Feb"<"Mar"<..: 1 1 1 1 1 1 1 1 1 1 ...
 $ late_departure: Factor w/ 2 levels "Late","Ontime/Early": 1 2 2 2 1 2 2 2 2 2 ...
 $ season        : Factor w/ 4 levels "Autumn","Spring",..: 4 4 4 4 4 4 4 4 4 4 ...
 - attr(*, "na.action")= 'omit' Named int [1:25159] 4 9 14 22 26 31 49 58 59 61 ...
  ..- attr(*, "names")= chr [1:25159] "4" "9" "14" "22" ...
# check split of the data
flights_test %>% 
  janitor::tabyl(late_departure)
 late_departure     n   percent
           Late  8117 0.4413092
   Ontime/Early 10276 0.5586908
flights_train %>% 
  janitor::tabyl(late_departure)
 late_departure     n   percent
           Late 32445 0.4409786
   Ontime/Early 41130 0.5590214

conf_mat <- flights_test_pred %>%
              conf_mat(truth = late_departure, estimate = pred)
conf_mat
              Truth
Prediction     Late Ontime/Early
  Late         4484         3136
  Ontime/Early 3633         7140
confusionMatrix(flights_test_pred$pred, flights_test_pred$late_departure)
Confusion Matrix and Statistics

              Reference
Prediction     Late Ontime/Early
  Late         4484         3136
  Ontime/Early 3633         7140
                                        
               Accuracy : 0.632         
                 95% CI : (0.625, 0.639)
    No Information Rate : 0.5587        
    P-Value [Acc > NIR] : < 2.2e-16     
                                        
                  Kappa : 0.2488        
                                        
 Mcnemar's Test P-Value : 1.653e-09     
                                        
            Sensitivity : 0.5524        
            Specificity : 0.6948        
         Pos Pred Value : 0.5885        
         Neg Pred Value : 0.6628        
             Prevalence : 0.4413        
         Detection Rate : 0.2438        
   Detection Prevalence : 0.4143        
      Balanced Accuracy : 0.6236        
                                        
       'Positive' Class : Late          
                                        
LS0tCnRpdGxlOiAiRmxpZ2h0cyBFeHBsb3JhdG9yeSBBbmFseXNpcyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKVGhlIHB1cnBvc2Ugb2YgZXhwbG9yYXRvcnkgYW5hbHlzaXMgaXMgdG8gcGVyZm9ybSBpbml0aWFsIGludmVzdGlnYXRpb25zIG9uIHRoZSBkYXRhIHNvIGFzIHRvIGRpc2NvdmVyIHBhdHRlcm5zLCBpZGVudGlmeSBhbnkgYW5vbWFsaWVzLCB0byB0ZXN0IGluaXRpYWwgaHlwb3RoZXNpcyBhbmQgY2hlY2sgYXNzdW1wdGlvbnMgbWFkZSBhdCB0aGUgc3RhcnQgb2YgdGhlIHByb2plY3QuIAoKSW4gdGhpcyBzZWN0aW9uIG9mIHRoZSBwcm9qZWN0IHdlIHdpbGwgYXNrIHR3byB0eXBlcyBvZiBxdWVzdGlvbnM6IAoKMS4gd2hhdCB0eXBlIG9mIHZhcmlhdGlvbiBvY2N1cnMgd2l0aGluIG15IHZhcmlhYmxlcz8gCjIuIHdoYXQgdHlwZSBvZiBjb3ZhcmlhdGlvbiBvY2N1cnMgYmV0d2VlbiBteSB2YXJpYWJsZXM/IAoKVmFyaWF0aW9uIGJlaW5nIHRoZSB0ZW5kZW5jeSBmb3IgdmFsdWVzIG9mIGEgdmFyaWFibGUgdG8gY2hhbmdlIGZyb20gbWVhc3VyZW1lbnQgdG8gbWVhc3VyZW1lbnQsIGFuZCBjb3ZhcmlhbmNlIGlzIHRoZSB0ZW5kZW5jeSBmb3IgdHdvIG9yIG1vcmUgdmFyaWFibGVzIHRvIHZhcnkgdG9nZXRoZXIgaW4gYSByZWxhdGVkIHdheS4KCmBgYHtyLCB3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9CnBhY21hbjo6cF9sb2FkKAogIHRpZHl2ZXJzZSwKICBoZXJlLAogIFJDb2xvckJyZXdlciwKICBsdWJyaWRhdGUsCiAgc2NhbGVzLAogIEdHYWxseSwKICBzdGF0cywKICBjb3JycGxvdCwKICBsZWFwcywKICBnbG11bHRpLAogIGJyb29tLAogIHJwYXJ0LAogIHJwYXJ0LnBsb3QsCiAgbW9kZWxyLAogIHlhcmRzdGljaywKICBjYXJldCwKICByYW5nZXIKKQpgYGAKCmBgYHtyLCB3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9CmZsaWdodHNfZHQgPC0gcmVhZF9jc3YoaGVyZSgiY2xlYW5fZGF0YS9mbGlnaHRzX2NsZWFuLmNzdiIpKQoKY2JQYWxldHRlIDwtIGMoIiM5OTk5OTkiLCAiI0U2OUYwMCIsICIjNTZCNEU5IiwgIiMwMDlFNzMiLCAiI0YwRTQ0MiIsICIjMDA3MkIyIiwgIiNENTVFMDAiLCAiI0NDNzlBNyIpCmBgYAoKIyBXaGljaCBhaXJwb3J0IGluIG91ciBkYXRhc2V0IGhhcyB0aGUgaGlnaGVzdCBudW1iZXIgb2YgZGVwYXJ0dXJlcz8KCmBgYHtyfQpmbGlnaHRzX2R0ICU+JSAKICBncm91cF9ieShvcmlnaW4pICU+JQogIGdncGxvdCgpICsKICBhZXMoeCA9IG9yaWdpbiwgZmlsbCA9IG9yaWdpbikgKwogIGdlb21fYmFyKCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNiUGFsZXR0ZSkgKwogIGxhYnMoCiAgICB4ID0gImFpcnBvcnQiLAogICAgeSA9ICJkZXBhcnR1cmUgbnVtYmVycyIsCiAgICB0aXRsZSA9ICJEZXBhcnR1cmUgbnVtYmVycyBieSBhaXJwb3J0IgogICkgKwogIGd1aWRlcyhmaWxsID0gIm5vbmUiKSArCiAgdGhlbWVfYncoKQpgYGAKCiMgV2hhdCBpcyB0aGUgdHJlbmQgb2YgZGVsYXlzIG92ZXIgdGhlIHllYXIsIGhvdyBkb2VzIGl0IGNvbXBhcmUgYWNyb3NzIHRoZSB0aHJlZSBhaXJwb3J0cz8KCmBgYHtyLHdhcm5pbmc9RkFMU0V9CmZsaWdodHNfZHQgJT4lIAogIGZpbHRlcihkZXBfZGVsYXkgPiAwKSAlPiUgCiAgZ3JvdXBfYnkobW9udGggPSBmbG9vcl9kYXRlKHNjaGVkX2RlcF90aW1lLCAibW9udGgiKSwgb3JpZ2luKSAlPiUgCiAgc3VtbWFyaXNlKG1lYW5fZGVsYXkgPSBtZWFuKGRlcF9kZWxheSksIC5ncm91cHMgPSAiZHJvcCIpICU+JSAKICBnZ3Bsb3QoKSArCiAgYWVzKHggPSBtb250aCwgeSA9IG1lYW5fZGVsYXksIGNvbG91ciA9IG9yaWdpbikgKwogIGdlb21fbGluZShhbHBoYSA9IDAuNikgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjgpICsKICBsYWJzKAogICAgeCA9ICJtb250aCIsCiAgICB5ID0gIm1lYW4gZGVsYXkgKG1pbnV0ZXMpIiwKICAgIHRpdGxlID0gIiBNZWFuIGRlbGF5IGJ5IG1vbnRoIiwKICAgIGNvbG91ciA9ICJhaXJwb3J0IgogICkgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiIzk5OTk5OSIsICIjRTY5RjAwIiwgIiM1NkI0RTkiKSkgKwogIHRoZW1lX2J3KCkKYGBgCgojIFdoYXQgaXMgdGhlIG51bWJlciBvZiBkZXBhcnR1cmUgZGVsYXlzIG92ZXIgdGhlIHllYXI/CgpgYGB7cn0KZmxpZ2h0c19kdCAlPiUKICBmaWx0ZXIoZGVwX2RlbGF5ID4gMCkgJT4lIAogIGdyb3VwX2J5KG1vbnRoID0gZmxvb3JfZGF0ZShzY2hlZF9kZXBfdGltZSwgIm1vbnRoIiksIG9yaWdpbikgJT4lIAogIHN1bW1hcmlzZShub19vZl9kZWxheXMgPSBuKCksIC5ncm91cHMgPSAiZHJvcCIpICU+JSAKICBnZ3Bsb3QoKSArCiAgYWVzKHggPSBtb250aCwgeSA9IG5vX29mX2RlbGF5cywgY29sb3VyID0gb3JpZ2luKSArCiAgZ2VvbV9saW5lKGFscGhhID0gMC42KSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuOCkgKwogIGxhYnMoCiAgICB4ID0gIm1vbnRoIiwKICAgIHkgPSAibnVtYmVyIG9mIGRlbGF5cyIsCiAgICB0aXRsZSA9ICIgTW9udGhseSB0cmVuZCBvZiBkZXBhcnR1cmUgZGVsYXlzIiwKICAgIGNvbG91ciA9ICJhaXJwb3J0IgogICkgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiIzk5OTk5OSIsICIjRTY5RjAwIiwgIiM1NkI0RTkiKSkgKwogIHRoZW1lX2J3KCkKYGBgCgojIFdoYXQgaXMgdGhlIG51bWJlciBvZiBmbGlnaHRzIHBlciBtb250aD8KCmBgYHtyfQpmbGlnaHRzX2R0ICU+JQogIG11dGF0ZShtb250aCA9IG1vbnRoKHNjaGVkX2RlcF90aW1lLCBsYWJlbCA9IFRSVUUpKSAlPiUgCiAgZ3JvdXBfYnkobW9udGgsIG9yaWdpbikgJT4lIAogIHN1bW1hcmlzZShub19vZl9mbGlnaHRzID0gbigpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgCiAgZ2dwbG90KCkgKwogIGFlcyh4ID0gbW9udGgsIHkgPSBub19vZl9mbGlnaHRzLCBmaWxsID0gb3JpZ2luKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiLCBhbHBoYSA9IDAuOCkgKwogIGxhYnMoCiAgICB4ID0gIm1vbnRoIiwKICAgIHkgPSAibnVtYmVyIG9mIGRlcGFydHVyZXMiLAogICAgdGl0bGUgPSAiRGVwYXJ0dXJlIG51bWJlcnMgYnkgbW9udGgiLAogICAgZmlsbCA9ICJhaXJwb3J0IgogICkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNiUGFsZXR0ZSkgKwogIHRoZW1lX2J3KCkKYGBgCgojIFdoaWNoIGNhcnJpZXIgaGFzIHRoZSBtb3N0IGRlcGFydHVyZSBkZWxheXM/CgpgYGB7cn0KZmxpZ2h0c19kdCAlPiUgCiAgZmlsdGVyKGRlcF9kZWxheSA+IDApICU+JSAKICBncm91cF9ieShjYXJyaWVyX25hbWUsIG9yaWdpbikgJT4lIAogIHN1bW1hcmlzZShtZWFuX2RlbGF5ID0gbWVhbihkZXBfZGVsYXkpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgCiAgZ2dwbG90KCkgKwogIGFlcyh4ID0gcmVvcmRlcihjYXJyaWVyX25hbWUsIG1lYW5fZGVsYXkpLCB5ID0gbWVhbl9kZWxheSwgZmlsbCA9IG9yaWdpbikgKwogIGdlb21fY29sKGFscGhhID0gMC44KSArCiAgZmFjZXRfd3JhcCh+IG9yaWdpbikgKwogIGxhYnMoCiAgICB4ID0gImNhcnJpZXIiLAogICAgeSA9ICJtZWFuIGRlbGF5IChtaW51dGVzKSIsCiAgICB0aXRsZSA9ICJNZWFuIGRlcGFydHVyZSBkZWxheSBieSBjYXJyaWVyIiwKICAgIGZpbGwgPSAiYWlycG9ydCIKICApICsKICB0aGVtZV9idygpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiIzk5OTk5OSIsICIjRTY5RjAwIiwgIiM1NkI0RTkiKSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgdmp1c3QgPSAwLjUsIGhqdXN0ID0gMSkpICsKICBjb29yZF9mbGlwKCkKYGBgCgojIFdoaWNoIGNhcnJpZXIgaGFzIHRoZSBtb3N0IGFycml2YWwgZGVsYXlzPwoKYGBge3J9CmZsaWdodHNfZHQgJT4lIAogIGZpbHRlcihhcnJfZGVsYXkgPiAwKSAlPiUgCiAgZ3JvdXBfYnkoY2Fycmllcl9uYW1lLCBvcmlnaW4pICU+JSAKICBzdW1tYXJpc2UobWVhbl9kZWxheSA9IG1lYW4oYXJyX2RlbGF5KSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lIAogIGdncGxvdCgpICsKICBhZXMoeCA9IHJlb3JkZXIoY2Fycmllcl9uYW1lLCBtZWFuX2RlbGF5KSwgeSA9IG1lYW5fZGVsYXksIGZpbGwgPSBvcmlnaW4pICsKICBnZW9tX2NvbChhbHBoYSA9IDAuOCkgKwogIGZhY2V0X3dyYXAofiBvcmlnaW4pICsKICBsYWJzKAogICAgeCA9ICJjYXJyaWVyIiwKICAgIHkgPSAibWVhbiBkZWxheSAobWludXRlcykiLAogICAgdGl0bGUgPSAiTWVhbiBhcnJpdmFsIGRlbGF5IGJ5IGNhcnJpZXIiLAogICAgZmlsbCA9ICJhaXJwb3J0IgogICkgKwogIHRoZW1lX2J3KCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCIjOTk5OTk5IiwgIiNFNjlGMDAiLCAiIzU2QjRFOSIpKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSkgKwogIGNvb3JkX2ZsaXAoKQpgYGAKCiMgV2hpY2ggc2Vhc29uIGhhcyB0aGUgaGlnaGVzdCBudW1iZXIgb2YgZGVwYXJ0dXJlIGRlbGF5cz8KCmBgYHtyfQpmbGlnaHRzX2R0ICU+JSAKICBmaWx0ZXIoZGVwX2RlbGF5ID4gMCkgJT4lIAogIGdyb3VwX2J5KGRheSA9IGZsb29yX2RhdGUoc2NoZWRfZGVwX3RpbWUsICJkYXkiKSwgb3JpZ2luKSAlPiUgCiAgc3VtbWFyaXNlKG1lYW5fZGVsYXkgPSBtZWFuKGRlcF9kZWxheSwgbmEucm0gPSBUUlVFKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lIAogIGdncGxvdCgpICsKICBhZXMoeCA9IGRheSwgeSA9IG1lYW5fZGVsYXksIGNvbG91ciA9IG9yaWdpbikgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjgpICsKICBsYWJzKAogICAgeCA9ICJkYXRlIiwKICAgIHkgPSAibWVhbiBkZWxheSAobWludXRlcykiLAogICAgdGl0bGUgPSAiTWVhbiBkZXBhcnR1cmUgZGVsYXkgYnkgbW9udGgiCiAgKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjOTk5OTk5IiwgIiNFNjlGMDAiLCAiIzU2QjRFOSIpKSArCiAgdGhlbWVfYncoKQpgYGAKCiMgT3ZlciB0aGUgY291cnNlIG9mIGEgZGF5IHdoZW4gaXMgdGhlIGxhcmdlc3QgYXZlcmFnZSBkZWxheT8KCmBgYHtyfQpmbGlnaHRzX2R0ICU+JSAKICBmaWx0ZXIoZGVwX2RlbGF5ID4gMCAmIG9yaWdpbiA9PSAiRVdSIikgJT4lIAogIHNlbGVjdChkZXBfZGVsYXksIGhvdXIpICU+JQogIGdyb3VwX2J5KGhvdXIpICU+JSAKICBzdW1tYXJpc2UobWVhbl9kZWxheSA9IG1lYW4oZGVwX2RlbGF5LCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgCiAgZ2dwbG90KCkgKwogIGFlcyh4ID0gaG91ciwgeSA9IG1lYW5fZGVsYXkpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC44LCBjb2xvdXIgPSAiIzU2QjRFOSIpICsKICBnZW9tX3Ntb290aChzZSA9IEZBTFNFLCBjb2xvdXIgPSAiI0U2OUYwMCIpICsKICBsYWJzKAogICAgeCA9ICJob3VyIiwKICAgIHkgPSAibWVhbiBkZWxheSAobWludXRlcykiLAogICAgdGl0bGUgPSAiTWVhbiBkZXBhcnR1cmUgZGVsYXkgYnkgZGVwYXJ0dXJlIHRpbWUiCiAgKSArCiAgdGhlbWVfYncoKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoNSwgMjMpLCBicmVha3MgPSBzZXEoNSwgMjMsIGJ5ID0gMSkpCmBgYAoKIyBXaGljaCBkYXkgaXMgdGhlIGJlc3QgZGF5IHRvIHRyYXZlbCBmcm9tIE5ld2FyayBJbnQuPwoKYGBge3J9CmZsaWdodHNfZHQgJT4lCiAgZmlsdGVyKGRlcF9kZWxheSA+IDAgJiBvcmlnaW4gPT0gIkVXUiIpICU+JSAKICBtdXRhdGUod2Vla2RheSA9IHdkYXkoc2NoZWRfZGVwX3RpbWUsIGxhYmVsID0gVFJVRSkpICU+JSAKICBncm91cF9ieSh3ZWVrZGF5KSAlPiUgCiAgc3VtbWFyaXNlKG1lYW5fZGVsYXkgPSBtZWFuKGRlcF9kZWxheSkpICU+JSAKICBnZ3Bsb3QoKSArCiAgYWVzKHggPSB3ZWVrZGF5LCB5ID0gbWVhbl9kZWxheSkgKwogICAgZ2VvbV9jb2woZmlsbCA9ICIjOTk5OTk5IiwgYWxwaGEgPSAwLjgpICsKICBsYWJzKAogICAgeCA9ICJ3ZWVrZGF5IiwKICAgIHkgPSAibWVhbiBkZXBhcnR1cmUgZGVsYXkgKG1pbnV0ZXMpIiwKICAgIHRpdGxlID0gIkRlcGFydHVyZSBkZWxheSBieSB3ZWVrZGF5IgogICkgKwogIHRoZW1lX2J3KCkKYGBgCgojIFdoaWNoIGFyZSB0aGUgbW9zdCBwb3B1bGFyIGRlc3RpbmF0aW9ucyBmcm9tIE5ld2FyayBJbnQ/CgpgYGB7cn0KZmxpZ2h0c19kdCAlPiUgCiAgZmlsdGVyKG9yaWdpbiA9PSAiRVdSIikgJT4lIAogIGdyb3VwX2J5KGRlc3QsIGRlc3RfbmFtZSkgJT4lIAogIHN1bW1hcmlzZShjb3VudCA9IG4oKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lIAogIGFycmFuZ2UoZGVzYyhjb3VudCkpICU+JSAKICBoZWFkKDEwKSAlPiUgCiAgZ2dwbG90KCkgKwogIGFlcyh4ID0gcmVvcmRlcihkZXN0X25hbWUsIGNvdW50KSwgeSA9IGNvdW50KSArCiAgZ2VvbV9jb2woZmlsbCA9ICIjOTk5OTk5IiwgYWxwaGEgPSAwLjgpICsKICBsYWJzKAogICAgeCA9ICJkZXN0aW5hdGlvbiIsCiAgICB5ID0gIm51bWJlciBvZiBmbGlnaHRzIHBlciB5ZWFyIiwKICAgIHRpdGxlID0gIkRlc3RpbmF0aW9ucyBmcm9tIE5ld2FyayBJbnQuIgogICkgKwogIHRoZW1lX2J3KCkgKwogIGNvb3JkX2ZsaXAoKQpgYGAKCiMgV2hpY2ggZGVzdGluYXRpb25zIHN1ZmZlciBmcm9tIHRoZSBsb25nZXN0IGRlbGF5cz8KCmBgYHtyfQpmbGlnaHRzX2R0ICU+JQogIGRyb3BfbmEoZGVzdF9uYW1lKSAlPiUgCiAgZmlsdGVyKGRlcF9kZWxheSA+IDAgJiBvcmlnaW4gPT0gIkVXUiIpICU+JSAKICBncm91cF9ieShkZXN0LCBkZXN0X25hbWUpICU+JSAKICBzdW1tYXJpc2UobWVhbl9kZWxheSA9IG1lYW4oZGVwX2RlbGF5LCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgCiAgYXJyYW5nZShkZXNjKG1lYW5fZGVsYXkpKSAlPiUgCiAgaGVhZCgxMCkgJT4lIAogIGdncGxvdCgpICsKICBhZXMoeCA9IHJlb3JkZXIoZGVzdF9uYW1lLCBtZWFuX2RlbGF5KSwgeSA9IG1lYW5fZGVsYXkpICsKICBnZW9tX2NvbChmaWxsID0gIiM5OTk5OTkiLCBhbHBoYSA9IDAuOCkgKwogIGxhYnMoCiAgICB4ID0gImRlc3RpbmF0aW9uIiwKICAgIHkgPSAibWVhbiBkZWxheSAobWludXRlcykiLAogICAgdGl0bGUgPSAiRGVzdGluYXRpb25zIHdpdGggbG9uZ2VzdCBkZWxheXMiCiAgKSArCiAgdGhlbWVfYncoKSArCiAgY29vcmRfZmxpcCgpCmBgYAoKIyBUcmVuZCB3ZWF0aGVyIGNvbmRpdGlvbnMgYWdhaW5zdCBtZWFuIGRlcGFydHVyZSBkZWxheXMKCmBgYHtyfQpmbGlnaHRzX2R0ICU+JSAKICBmaWx0ZXIoZGVwX2RlbGF5ID4gMCAmIG9yaWdpbiA9PSAiRVdSIikgJT4lIAogIGdyb3VwX2J5KGRheSA9IGZsb29yX2RhdGUoc2NoZWRfZGVwX3RpbWUsICJkYXkiKSwgb3JpZ2luKSAlPiUgCiAgc3VtbWFyaXNlKG1lYW5fdmlzaWJpbGl0eSA9IG1lYW4odmlzaWIsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIG1lYW5fZGVsYXkgPSBtZWFuKGRlcF9kZWxheSksIC5ncm91cHMgPSAiZHJvcCIpICU+JSAKICBnZ3Bsb3QoKSArCiAgYWVzKHggPSBtZWFuX3Zpc2liaWxpdHksIHkgPSBtZWFuX2RlbGF5KSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNykgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG91ciA9ICIjRTY5RjAwIikgKwogIGxhYnMoCiAgICB4ID0gIm1lYW4gdmlzaWJpbGl0eSAobWlsZXMpIiwKICAgIHkgPSAibWVhbiBkZXBhcnR1cmUgZGVsYXkgKG1pbnV0ZXMpIiwKICAgIHRpdGxlID0gIk1lYW4gZGVwYXJ0dXJlIGRlbGF5IGJ5IHZpc2liaWxpdHkiCiAgKSArCiAgdGhlbWVfYncoKQpgYGAKCmBgYHtyfQpmbGlnaHRzX2R0ICU+JSAKICBmaWx0ZXIoZGVwX2RlbGF5ID4gMCAmIG9yaWdpbiA9PSAiRVdSIikgJT4lIAogIGdyb3VwX2J5KGRheSA9IGZsb29yX2RhdGUoc2NoZWRfZGVwX3RpbWUsICJkYXkiKSwgb3JpZ2luKSAlPiUgCiAgc3VtbWFyaXNlKG1lYW5fd2luZF9zcGVlZCA9IG1lYW4od2luZF9zcGVlZCwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgbWVhbl9kZWxheSA9IG1lYW4oZGVwX2RlbGF5KSkgJT4lIAogIGdncGxvdCgpICsKICBhZXMoeCA9IG1lYW5fd2luZF9zcGVlZCwgeSA9IG1lYW5fZGVsYXkpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC43KSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3VyID0gIiNFNjlGMDAiKSArCiAgbGFicygKICAgIHggPSAibWVhbiB3aW5kIHNwZWVkIChtcGgpIiwKICAgIHkgPSAibWVhbiBkZXBhcnR1cmUgZGVsYXkgKG1pbnV0ZXMpIiwKICAgIHRpdGxlID0gIk1lYW4gZGVwYXJ0dXJlIGRlbGF5IGJ5IHdpbmQgc3BlZWQiCiAgKSArCiAgdGhlbWVfYncoKQpgYGAKCmBgYHtyfQpmbGlnaHRzX2R0ICU+JSAKICBmaWx0ZXIoZGVwX2RlbGF5ID4gMCAmIG9yaWdpbiA9PSAiRVdSIikgJT4lIAogIGdyb3VwX2J5KGRheSA9IGZsb29yX2RhdGUoc2NoZWRfZGVwX3RpbWUsICJkYXkiKSwgb3JpZ2luKSAlPiUgCiAgc3VtbWFyaXNlKG1lYW5fd2luZF9kaXIgPSBtZWFuKHdpbmRfZGlyLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBtZWFuX2RlbGF5ID0gbWVhbihkZXBfZGVsYXkpKSAlPiUgCiAgZ2dwbG90KCkgKwogIGFlcyh4ID0gbWVhbl93aW5kX2RpciwgeSA9IG1lYW5fZGVsYXkpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC43KSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3VyID0gIiNFNjlGMDAiKSArCiAgbGFicygKICAgIHggPSAibWVhbiB3aW5kIGRpcmVjdGlvbiAoZGVncmVlcykiLAogICAgeSA9ICJtZWFuIGRlcGFydHVyZSBkZWxheSAobWludXRlcykiLAogICAgdGl0bGUgPSAiTWVhbiBkZXBhcnR1cmUgZGVsYXkgYnkgd2luZCBkaXJlY3Rpb24iCiAgKSArCiAgdGhlbWVfYncoKQpgYGAKCmBgYHtyfQpmbGlnaHRzX2R0ICU+JQogIGZpbHRlcihkZXBfZGVsYXkgPiAwICYgb3JpZ2luID09ICJFV1IiKSAlPiUgCiAgZ3JvdXBfYnkoZGF5ID0gZmxvb3JfZGF0ZShzY2hlZF9kZXBfdGltZSwgImRheSIpLCBvcmlnaW4pICU+JSAKICBzdW1tYXJpc2UobWVhbl9odW1pZGl0eSA9IG1lYW4oaHVtaWQsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIG1lYW5fZGVsYXkgPSBtZWFuKGRlcF9kZWxheSkpICU+JSAKICBnZ3Bsb3QoKSArCiAgYWVzKHggPSBtZWFuX2h1bWlkaXR5LCB5ID0gbWVhbl9kZWxheSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjcpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2xvdXIgPSAiI0U2OUYwMCIpICsKICBsYWJzKAogICAgeCA9ICJtZWFuIGh1bWlkaXR5ICglKSIsCiAgICB5ID0gIm1lYW4gZGVwYXJ0dXJlIGRlbGF5IChtaW51dGVzKSIsCiAgICB0aXRsZSA9ICJNZWFuIGRlcGFydHVyZSBkZWxheSBieSBodW1pZGl0eSIKICApICsKICB0aGVtZV9idygpCmBgYAoKYGBge3J9CmZsaWdodHNfZHQgJT4lIAogIGZpbHRlcihkZXBfZGVsYXkgPiAwICYgb3JpZ2luID09ICJFV1IiKSAlPiUgCiAgZ3JvdXBfYnkoZGF5ID0gZmxvb3JfZGF0ZShzY2hlZF9kZXBfdGltZSwgImRheSIpLCBvcmlnaW4pICU+JSAKICBzdW1tYXJpc2UobWVhbl90ZW1wID0gbWVhbih0ZW1wLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBtZWFuX2RlbGF5ID0gbWVhbihkZXBfZGVsYXkpKSAlPiUgCiAgZ2dwbG90KCkgKwogIGFlcyh4ID0gbWVhbl90ZW1wLCB5ID0gbWVhbl9kZWxheSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjcpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2xvdXIgPSAiI0U2OUYwMCIpICsKICBsYWJzKAogICAgeCA9ICJtZWFuIHRlbXBlcmF0dXJlIChkZWdmKSIsCiAgICB5ID0gIm1lYW4gZGVwYXJ0dXJlIGRlbGF5IChtaW51dGVzKSIsCiAgICB0aXRsZSA9ICJNZWFuIGRlcGFydHVyZSBkZWxheSBieSB0ZW1wZXJhdHVyZSIKICApICsKICB0aGVtZV9idygpCmBgYAoKYGBge3J9CmZsaWdodHNfZHQgJT4lIAogIGZpbHRlcihkZXBfZGVsYXkgPiAwICYgb3JpZ2luID09ICJFV1IiKSAlPiUgCiAgZ3JvdXBfYnkoZGF5ID0gZmxvb3JfZGF0ZShzY2hlZF9kZXBfdGltZSwgImRheSIpLCBvcmlnaW4pICU+JSAKICBzdW1tYXJpc2UobWVhbl9kZXdwb2ludCA9IG1lYW4oZGV3cCwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgbWVhbl9kZWxheSA9IG1lYW4oZGVwX2RlbGF5KSkgJT4lIAogIGdncGxvdCgpICsKICBhZXMoeCA9IG1lYW5fZGV3cG9pbnQsIHkgPSBtZWFuX2RlbGF5KSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNykgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG91ciA9ICIjRTY5RjAwIikgKwogIGxhYnMoCiAgICB4ID0gIm1lYW4gZGV3cG9pbnQgKGRlZ0YpIiwKICAgIHkgPSAibWVhbiBkZXBhcnR1cmUgZGVsYXkgKG1pbnV0ZXMpIiwKICAgIHRpdGxlID0gIk1lYW4gZGVwYXJ0dXJlIGRlbGF5IGJ5IGRld3BvaW50IgogICkgKwogIHRoZW1lX2J3KCkKYGBgCgpgYGB7cn0KZmxpZ2h0c19kdCAlPiUgCiAgZmlsdGVyKGRlcF9kZWxheSA+IDAgJiBvcmlnaW4gPT0gIkVXUiIpICU+JSAKICBncm91cF9ieShkYXkgPSBmbG9vcl9kYXRlKHNjaGVkX2RlcF90aW1lLCAiZGF5IiksIG9yaWdpbikgJT4lIAogIHN1bW1hcmlzZShtZWFuX3ByZWNpcCA9IG1lYW4ocHJlY2lwLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBtZWFuX2RlbGF5ID0gbWVhbihkZXBfZGVsYXkpKSAlPiUgCiAgZ2dwbG90KCkgKwogIGFlcyh4ID0gbWVhbl9wcmVjaXAsIHkgPSBtZWFuX2RlbGF5KSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNykgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG91ciA9ICIjRTY5RjAwIikgKwogIGxhYnMoCiAgICB4ID0gIm1lYW4gcHJlY2lwaXRhdGlvbiAoaW5jaGVzKSIsCiAgICB5ID0gIm1lYW4gZGVwYXJ0dXJlIGRlbGF5IChtaW51dGVzKSIsCiAgICB0aXRsZSA9ICJNZWFuIGRlcGFydHVyZSBkZWxheSBieSBwcmVjaXBpdGF0aW9uIgogICkgKwogIHRoZW1lX2J3KCkKYGBgCgpgYGB7cn0KZmxpZ2h0c19kdCAlPiUKICBmaWx0ZXIoZGVwX2RlbGF5ID4gMCAmIG9yaWdpbiA9PSAiRVdSIikgJT4lIAogIGdyb3VwX2J5KGRheSA9IGZsb29yX2RhdGUoc2NoZWRfZGVwX3RpbWUsICJkYXkiKSwgb3JpZ2luKSAlPiUgCiAgc3VtbWFyaXNlKG1lYW5fcHJlc3N1cmUgPSBtZWFuKHByZXNzdXJlLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBtZWFuX2RlbGF5ID0gbWVhbihkZXBfZGVsYXkpKSAlPiUgCiAgZ2dwbG90KCkgKwogIGFlcyh4ID0gbWVhbl9wcmVzc3VyZSwgeSA9IG1lYW5fZGVsYXkpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC43KSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3VyID0gIiNFNjlGMDAiKSArCiAgbGFicygKICAgIHggPSAibWVhbiBwcmVzc3VyZSAobWJhcikiLAogICAgeSA9ICJtZWFuIGRlcGFydHVyZSBkZWxheSAobWludXRlcykiLAogICAgdGl0bGUgPSAiTWVhbiBkZXBhcnR1cmUgZGVsYXkgYnkgcHJlc3N1cmUiCiAgKSArCiAgdGhlbWVfYncoKQpgYGAKCiMgQ29ycnBsb3QKCmBgYHtyfQojIHN1YnNldCB0aGUgZmxpZ2h0cyBkYXRhc2V0IHNvIGFzIHRvIGRyb3AgTkFzLCBmaWx0ZXIgb24gb25seSBkZXBhcnR1cmUgZGVsYXlzIChubyBlYXJseSBkZXBhcnR1cmVzKSBhbmQgb25seSBmb3IgTmV3YXJrIEludC4KZmxpZ2h0c193ZWF0aGVyIDwtIGZsaWdodHNfZHQgJT4lIAogIG5hLm9taXQoKSAlPiUgCiAgZmlsdGVyKGRlcF9kZWxheSA+IDAgJiBvcmlnaW4gPT0gIkVXUiIpICU+JSAKICBzZWxlY3QoZGVwX2RlbGF5LCB0ZW1wLCBkZXdwLCBodW1pZCwgd2luZF9kaXIsIHdpbmRfc3BlZWQsIHByZWNpcCwgcHJlc3N1cmUsIHZpc2liKQoKIyBjcmVhdGUgY29ycmVsYXRpb24gbWF0cml4CmNvcl9tYXRyaXggPC0gY29yKGZsaWdodHNfd2VhdGhlcikKY29ycnBsb3QoY29yX21hdHJpeCwgdHlwZSA9ICJ1cHBlciIsIGNvbCA9IGNiUGFsZXR0ZSwKICAgICAgICAgdGwuY29sID0gImJsYWNrIiwgbWV0aG9kID0gIm51bWJlciIpCmBgYAoKIyBnZ3BhaXJzCgpgYGB7cn0KZ2dwYWlycyhmbGlnaHRzX3dlYXRoZXIpCmBgYAoKIyBMaW5lYXIgcmVncmVzc2lvbiBtb2RlbGluZwoKYGBge3J9Cm1vZGVsXzFfZHQgPC0gZmxpZ2h0c19kdCAlPiUgCiAgbmEub21pdCgpICU+JSAKICBmaWx0ZXIoZGVwX2RlbGF5ID4gMCAmIG9yaWdpbiA9PSAiRVdSIikgJT4lIAogIHNlbGVjdChkZXBfZGVsYXksIHRlbXAsIGRld3AsIGh1bWlkLCB3aW5kX2Rpciwgd2luZF9zcGVlZCwgcHJlY2lwLCBwcmVzc3VyZSwgdmlzaWIpCm1vZGVsXzEgPC0gbG0oZGVwX2RlbGF5IH4gLiwgZGF0YSA9IG1vZGVsXzFfZHQpCnN1bW1hcnkobW9kZWxfMSkKYGBgCgpgYGB7cn0KbW9kZWxfMl9kdCA8LSBmbGlnaHRzX2R0ICU+JQogIGZpbHRlcihkZXBfZGVsYXkgPiAwICYgb3JpZ2luID09ICJFV1IiKSAlPiUgCiAgbmEub21pdCgpICU+JSAKICBzZWxlY3RfaWYoLiwgaXMubnVtZXJpYykgJT4lIAogIHNlbGVjdCgtYyhhcnJfZGVsYXksIGVuZ2luZXMsIHNlYXRzLCBsYXQsIGxvbiwgd2luZF9kaXIsIHllYXIsIHByZWNpcCwgbWludXRlLCBkaXN0YW5jZSwgZmxpZ2h0KSkKCm1vZGVsXzIgPC0gbG0oZGVwX2RlbGF5IH4gLiwgZGF0YSA9IG1vZGVsXzJfZHQpCnN1bW1hcnkobW9kZWxfMikKYGBgCgojIFJlbGF0aW9uc2hpcCBiZXR3ZWVuIHdlYXRoZXIgdmFyaWFibGVzCgpgYGB7cn0KZmxpZ2h0c19kdCAlPiUKICBmaWx0ZXIoZGVwX2RlbGF5ID4gMCAmIG9yaWdpbiA9PSAiRVdSIikgJT4lIAogIG5hLm9taXQoKSAlPiUgCiAgZ2dwbG90KCkgKwogIGFlcyh4ID0gaHVtaWQsIHkgPSBkZXdwKSArCiAgZ2VvbV9wb2ludCgpCgpmbGlnaHRzX2R0ICU+JQogIGZpbHRlcihkZXBfZGVsYXkgPiAwICYgb3JpZ2luID09ICJFV1IiKSAlPiUgCiAgbmEub21pdCgpICU+JSAKICBnZ3Bsb3QoKSArCiAgYWVzKHggPSB0ZW1wLCB5ID0gZGV3cCkgKwogIGdlb21fcG9pbnQoKQoKZmxpZ2h0c19kdCAlPiUKICBmaWx0ZXIoZGVwX2RlbGF5ID4gMCAmIG9yaWdpbiA9PSAiRVdSIikgJT4lIAogIG5hLm9taXQoKSAlPiUgCiAgZ2dwbG90KCkgKwogIGFlcyh4ID0gdmlzaWIsIHkgPSBodW1pZCkgKwogIGdlb21fcG9pbnQoKQoKZmxpZ2h0c19kdCAlPiUKICBmaWx0ZXIoZGVwX2RlbGF5ID4gMCAmIG9yaWdpbiA9PSAiRVdSIikgJT4lIAogIG5hLm9taXQoKSAlPiUgCiAgZ2dwbG90KCkgKwogIGFlcyh4ID0gZGV3cCwgeSA9IHByZXNzdXJlKSArCiAgZ2VvbV9wb2ludCgpCgpmbGlnaHRzX2R0ICU+JQogIGZpbHRlcihkZXBfZGVsYXkgPiAwICYgb3JpZ2luID09ICJFV1IiKSAlPiUgCiAgbmEub21pdCgpICU+JSAKICBnZ3Bsb3QoKSArCiAgYWVzKHggPSBodW1pZCwgeSA9IHdpbmRfc3BlZWQpICsKICBnZW9tX3BvaW50KCkKYGBgCgojIExpbmVhciByZWdyZXNzaW9uIG1vZGVsIHdpdGggaW50ZXJhY3Rpb25zIGluIHdlYXRoZXIgdmFyaWFibGVzCgpgYGB7cn0KbW9kZWxfMyA8LSBsbShkZXBfZGVsYXkgfiBhaXJfdGltZSArIGFpcmNyYWZ0X2FnZSArIGFsdCArIGhvdXIgKyBkZXdwICsKICAgICAgICAgICAgICBwcmVzc3VyZSArIGRld3A6aHVtaWQgKyBwcmVzc3VyZTpkZXdwICsgZGV3cDp0ZW1wICsgIAogICAgICAgICAgICAgIHdpbmRfc3BlZWQ6aHVtaWQsIAogICAgICAgICAgICAgIGRhdGEgPSBtb2RlbF8yX2R0KQpzdW1tYXJ5KG1vZGVsXzMpCmBgYAoKIyBnbG11bHRpCgpgYGB7cn0KZ2xtdWx0aV9maXQgPC0gZ2xtdWx0aSgKICBkZXBfZGVsYXkgfiAuLCAKICBkYXRhID0gZmxpZ2h0c193ZWF0aGVyLAogIGxldmVsID0gMiwgIyAyID0gaW5jbHVkZSBwYWlyd2lzZSBpbnRlcmFjdGlvbnMsIDEgPSBtYWluIGVmZmVjdHMgb25seSAobWFpbiBlZmZlY3QgPSBubyBwYWlyd2lzZSBpbnRlcmFjdGlvbnMpCiAgbWluc2l6ZSA9IDAsICMgbm8gbWluIHNpemUgb2YgbW9kZWwKICBtYXhzaXplID0gLTEsICMgLTEgPSBubyBtYXggc2l6ZSBvZiBtb2RlbAogIG1hcmdpbmFsaXR5ID0gVFJVRSwgIyBtYXJnaW5hbGl0eSBoZXJlIG1lYW5zIHRoZSBzYW1lIGFzICdzdHJvbmdseSBoaWVyYXJjaGljYWwnIGludGVyYWN0aW9ucywgaS5lLiBpbmNsdWRlIHBhaXJ3aXNlIGludGVyYWN0aW9ucyBvbmx5IGlmIGJvdGggcHJlZGljdG9ycyBwcmVzZW50IGluIHRoZSBtb2RlbCBhcyBtYWluIGVmZmVjdHMuCiAgbWV0aG9kID0gImciLCAjIHRoZSBwcm9ibGVtIGlzIHRvbyBsYXJnZSBmb3IgZXhoYXVzdGl2ZSBzZWFyY2gsIHNvIHNlYXJjaCB1c2luZyBhIGdlbmV0aWMgYWxnb3JpdGhtCiAgY3JpdCA9IGJpYywgIyBjcml0ZXJpYSBmb3IgbW9kZWwgc2VsZWN0aW9uIGlzIEJJQyB2YWx1ZSAobG93ZXIgaXMgYmV0dGVyKQogIHBsb3R0eSA9IEZBTFNFLCAjIGRvbid0IHBsb3QgbW9kZWxzIGFzIGZ1bmN0aW9uIHJ1bnMKICByZXBvcnQgPSBUUlVFLCAjIGRvIHByb2R1Y2UgcmVwb3J0cyBhcyBmdW5jdGlvbiBydW5zCiAgY29uZnNldHNpemUgPSAxMCwgIyByZXR1cm4gYmVzdCAxMDAgc29sdXRpb25zCiAgZml0ZnVuY3Rpb24gPSBsbSAjIGZpdCB1c2luZyB0aGUgYGxtYCBmdW5jdGlvbgopCmBgYAoKIyBEZWNpc2lvbiBUcmVlCgpgYGB7cn0KZmxpZ2h0c19kZWNpc2lvbl90cmVlIDwtIGZsaWdodHNfZHQgJT4lCiAgZmlsdGVyKG9yaWdpbiA9PSAiRVdSIikgJT4lIAogIHNlbGVjdChzY2hlZF9kZXBfdGltZSwgZGVwX2RlbGF5LCBkaXN0YW5jZSwgZW5naW5lcywgZW5naW5lLCAKICAgICAgICAgYWlyY3JhZnRfYWdlLCBsYXQsIGxvbiwgYWx0LCBob3VyLCB0ZW1wLCBwcmVjaXAsIGh1bWlkLCB2aXNpYiwgcHJlc3N1cmUsCiAgICAgICAgIGRld3AsIHdpbmRfZGlyLCB3aW5kX3NwZWVkKSAlPiUgCiAgbXV0YXRlKGVuZ2luZXMgPSBmYWN0b3IoZW5naW5lcyksCiAgICAgICAgIGVuZ2luZSA9IGZhY3RvcihlbmdpbmUpLAogICAgICAgICBtb250aCA9IG1vbnRoKHNjaGVkX2RlcF90aW1lLCBsYWJlbCA9IFRSVUUpLAogICAgICAgICBsYXRlX2RlcGFydHVyZSA9IGFzLmZhY3RvcihpZmVsc2UoZGVwX2RlbGF5ID4gMCwgIkxhdGUiLCAiT250aW1lL0Vhcmx5IikpKSAlPiUKICBtdXRhdGUoc2Vhc29uID0gZmFjdG9yKGNhc2Vfd2hlbigKICAgIG1vbnRoICVpbiUgYygiRGVjIiwgIkphbiIsICJGZWIiKSB+ICJXaW50ZXIiLAogICAgbW9udGggJWluJSBjKCJNYXIiLCAiQXByIiwgIk1heSIpIH4gIlNwcmluZyIsCiAgICBtb250aCAlaW4lIGMoIkp1biIsICJKdWwiLCAiQXVnIikgfiAiU3VtbWVyIiwKICAgIG1vbnRoICVpbiUgYygiU2VwIiwgIk9jdCIsICJOb3YiKSB+ICJBdXR1bW4iCiAgKSkpICU+JSAKICBzZWxlY3QoLWMoZGVwX2RlbGF5LCBzY2hlZF9kZXBfdGltZSkpICU+JSAKICBuYS5vbWl0KCkKCnN0cihmbGlnaHRzX2RlY2lzaW9uX3RyZWUpCgojIHNldC5zZWVkKDE5KQoKbl9kYXRhIDwtIG5yb3coZmxpZ2h0c19kZWNpc2lvbl90cmVlKQojIGNyZWF0ZSB0ZXN0IHNhbXBsZSBpbmRleAp0ZXN0X2luZGV4IDwtIHNhbXBsZSgxOm5fZGF0YSwgc2l6ZSA9IG5fZGF0YSAqIDAuMikKIyBjcmVhdGUgdGVzdCBzZXQKZmxpZ2h0c190ZXN0IDwtIHNsaWNlKGZsaWdodHNfZGVjaXNpb25fdHJlZSwgdGVzdF9pbmRleCkKIyBjcmVhdGUgdHJhaW5pbmcgc2V0CmZsaWdodHNfdHJhaW4gPC0gc2xpY2UoZmxpZ2h0c19kZWNpc2lvbl90cmVlLCAtdGVzdF9pbmRleCkKYGBgCgpgYGB7cn0KIyBjaGVjayBzcGxpdCBvZiB0aGUgZGF0YQpmbGlnaHRzX3Rlc3QgJT4lIAogIGphbml0b3I6OnRhYnlsKGxhdGVfZGVwYXJ0dXJlKQoKZmxpZ2h0c190cmFpbiAlPiUgCiAgamFuaXRvcjo6dGFieWwobGF0ZV9kZXBhcnR1cmUpCmBgYAoKYGBge3J9CmZsaWdodHNfZml0IDwtIHJwYXJ0KAogIGZvcm11bGEgPSBsYXRlX2RlcGFydHVyZSB+IC4sIAogIGRhdGEgPSBmbGlnaHRzX3RyYWluLCAKICBtZXRob2QgPSAnY2xhc3MnCikKCnJwYXJ0LnBsb3QoZmxpZ2h0c19maXQsIAogICAgICAgICAgIHllc25vID0gMiwgCiAgICAgICAgICAgZmFsbGVuLmxlYXZlcyA9IFRSVUUsIAogICAgICAgICAgIGZhY2xlbiA9IDIsIAogICAgICAgICAgIGRpZ2l0cyA9IDQpCmBgYAoKYGBge3J9CmZsaWdodHNfdGVzdF9wcmVkIDwtIGZsaWdodHNfdGVzdCAlPiUKICBhZGRfcHJlZGljdGlvbnMoZmxpZ2h0c19maXQsIHR5cGUgPSAnY2xhc3MnKQoKZmxpZ2h0c190ZXN0X3ByZWQKYGBgCgpgYGB7cn0KY29uZl9tYXQgPC0gZmxpZ2h0c190ZXN0X3ByZWQgJT4lCiAgICAgICAgICAgICAgY29uZl9tYXQodHJ1dGggPSBsYXRlX2RlcGFydHVyZSwgZXN0aW1hdGUgPSBwcmVkKQpjb25mX21hdApgYGAKCmBgYHtyfQpjb25mdXNpb25NYXRyaXgoZmxpZ2h0c190ZXN0X3ByZWQkcHJlZCwgZmxpZ2h0c190ZXN0X3ByZWQkbGF0ZV9kZXBhcnR1cmUpCmBgYAoK